﻿// 2023/3/20: 首个版本
// 2023/9/25: 改为直接输入Icon对象
// 2024/6/25: 支持API3，支持异步
// 2024/6/28: 恢复方法名

using System;
using System.Collections.Generic;
using System.Linq;
using ASEva;
using ASEva.Samples;
using ASEva.UIEto;
using Eto.Forms;
using Eto.Drawing;
using System.Threading.Tasks;

namespace CommonSource
{
    class SignedSignalChooser : DialogPanel
    {
        public SignedSignalChooser(String originValueSignalID, String originSignSignalID, double? originSignalScale, String unit, Icon icon = null)
        {
            currentValueSignal = originValueSignalID;
            currentSignSignal = originSignSignalID;
            currentScale = originSignalScale;

            Icon = icon;
            Title = chinese ? "带符号位信号选择" : "Select Signal with Sign Bit";
            SetFixMode(460, 630, true);

            var mainLayout = this.SetContentAsColumnLayout();
            searchBox = mainLayout.AddControl(new SearchBox()) as SearchBox;
            treeView = mainLayout.AddControl(new SimpleTreeView(), true) as SimpleTreeView;

            TextBox textScale = null;
            if (currentScale != null)
            {
                var unitLayout = mainLayout.AddRowLayout();
                unitLayout.AddLabel(chinese ? "数值 x" : "Value x");
                textScale = unitLayout.AddControl(new TextBox{ Text = currentScale.Value.ToString(), TextColor = Colors.Green }, true) as TextBox;
                if (!String.IsNullOrEmpty(unit)) unitLayout.AddLabel(unit);
            }

            var signedLayout = mainLayout.AddRowLayout();
            signedLayout.AddLabel(chinese ? "符号位信号：" : "Sign bit signal:");
            var linkSigned = signedLayout.AddLinkButton("--", true);

            Button buttonDelete = null;
            var buttonLayout = mainLayout.AddRowLayout();
            if (currentValueSignal != null) buttonDelete = buttonLayout.AddButton(chinese ? "删除" : "Delete", false, 100);
            buttonLayout.AddSpace();
            buttonSelect = buttonLayout.AddButton(chinese ? "确认" : "OK", false, 100);

            initTreeView();
            updateSignedLinkProps(linkSigned);

            searchBox.TextChanged += async delegate
            {
                noAvailables = !rebuildTreeView(await AgencyAsync.GetSignalTree(), searchBox.Text.ToLower(), false);
                if (noAvailables)
                {
                    buttonSelect.Enabled = false;
                    addNoAvailables();
                }
            };

            if (buttonDelete != null)
            {
                buttonDelete.Click += delegate
                {
                    Result = ResultType.Delete;
                    Close();
                };
            }

            buttonSelect.Click += delegate
            {
                Result = ResultType.Select;
                Close();
            };

            treeView.SelectedItemChanged += delegate
            {
                if (noAvailables) return;

                var key = treeView.GetSelectedKey();
                bool isMultiplexedEntry = key is String;

                String currentValueSignalUpdate = null;
                if (key is SignalTreeNode)
                {
                    var nodeType = (key as SignalTreeNode).Type;
                    if ((int)nodeType >= (int)SignalTreeNodeType.GeneralSignal) currentValueSignalUpdate = (key as SignalTreeNode).ID;
                }

                if (!isMultiplexedEntry) currentValueSignal = currentValueSignalUpdate;

                buttonSelect.Enabled = !isMultiplexedEntry && currentValueSignal != null;
            };

            treeView.SelectedItemActivated += delegate
            {
                if (buttonSelect.Enabled)
                {
                    Result = ResultType.Select;
                    Close();
                }
                else
                {
                    var key = treeView.GetSelectedKey();
                    if (key != null && key is String) searchBox.Text = (key as String) + ".all";
                }
            };

            if (textScale != null)
            {
                textScale.TextChanged += delegate
                {
                    bool scaleOK = true;
                    try
                    {
                        if (textScale.Text.Length == 0) scaleOK = false;
                        else
                        {
                            var val = Convert.ToDouble(textScale.Text);
                            if (val == 0) scaleOK = false;
                            else currentScale = val;
                        }
                    }
                    catch (Exception) { scaleOK = false; }
                    textScale.TextColor = scaleOK ? Colors.Green : Colors.Red;
                    buttonSelect.Enabled = scaleOK && currentValueSignal != null;
                };

                textScale.LostFocus += delegate
                {
                    textScale.Text = currentScale == null ? "1.0" : currentScale.Value.ToString();
                    textScale.TextColor = Colors.Green;
                };

                textScale.KeyDown += (o, e) =>
                {
                    if (e.Key == Keys.Enter && buttonSelect.Enabled)
                    {
                        Result = ResultType.Select;
                        Close();
                    }
                };
            }

            linkSigned.Click += async delegate
            {
                var dialog = new SignalChooser(currentSignSignal, null, null, icon);
                await App.RunDialog(dialog);

                if (dialog.Result == SignalChooser.ResultType.Delete) currentSignSignal = null;
                else if (dialog.Result == SignalChooser.ResultType.Select) currentSignSignal = dialog.SelectedSignal.SignalID;

                updateSignedLinkProps(linkSigned);
            };
        }

        public enum ResultType
        {
            Cancel = 0,
            Select = 1,
            Delete = 2,
        }

        public ResultType Result { get; set; }

        public SignalConfig SelectedSignal
        {
            get
            {
                return new SignalConfig()
                {
                    SignalID = currentValueSignal == null ? null : currentValueSignal.Clone() as String,
                    SignBitSignalID = currentSignSignal == null ? null : currentSignSignal.Clone() as String,
                    Scale = currentScale == null ? null : (double?)currentScale.Value,
                };
            }
        }

        private async void initTreeView()
        {
            searchBox.Enabled = buttonSelect.Enabled = false;

            if (rebuildTreeView(await AgencyAsync.GetSignalTree(), "", true))
            {
                searchBox.Enabled = true;
                buttonSelect.Enabled = currentValueSignal != null;
            }
            else addNoAvailables();
        }

        private bool rebuildTreeView(SignalTreeNode[] tops, String key, bool init)
        {
            var topNodes = new List<SimpleTreeNode>();
            var itemAdded = false;
            bool keyValid = key.Length >= 2;
            object keyToSelect = null;

            foreach (var top in tops)
            {
                var topMatch = keyValid && (top.ID.ToLower().Contains(key) || top.Name.ToLower().Contains(key));

                var topNode = new SimpleTreeNode{ Key = top, Text = top.Name };
                var shouldAddTopNode = !keyValid || topMatch;

                foreach (var middle in top.Children)
                {
                    var middleMatch = keyValid && (middle.ID.ToLower().Contains(key) || middle.Name.ToLower().Contains(key));
                    var bottomAllMatch = keyValid && (key == middle.ID.ToLower() + ".all");

                    var middleNode = new SimpleTreeNode{ Key = middle, Text = middle.Name };
                    bool shouldAddMiddleNode = !keyValid || topMatch || middleMatch;

                    String multiplexedTarget = null;
                    foreach (var bottom in middle.Children)
                    {
                        var bottomMatch = keyValid && (bottom.ID.ToLower().Contains(key) || bottom.Name.ToLower().Contains(key));

                        SimpleTreeNode bottomNode = null;
                        if (bottom.Type == SignalTreeNodeType.MultiplexedBusSignal)
                        {
                            var isCurrent = currentValueSignal != null && bottom.ID == currentValueSignal;
                            if (bottomAllMatch)
                            {
                                bottomNode = new SimpleTreeNode{ Key = bottom, Text = bottom.Name };
                                if (isCurrent)
                                {
                                    bottomNode.TextColor = Colors.Green;
                                    keyToSelect = bottomNode.Key;
                                }
                                else bottomNode.TextColor = Colors.Blue;
                            }
                            else
                            {
                                if (init && isCurrent)
                                {
                                    var searchKey = middle.ID.ToLower() + ".all";
                                    searchBox.Text = searchKey;
                                    return rebuildTreeView(tops, searchKey, false);
                                }
                                if (shouldAddMiddleNode) multiplexedTarget = middle.ID;
                            }
                        }
                        else
                        {
                            var shouldAddBottomNode = !keyValid || topMatch || middleMatch || bottomMatch || bottomAllMatch;
                            if (shouldAddBottomNode)
                            {
                                bottomNode = new SimpleTreeNode{ Key = bottom, Text = bottom.Name };
                                if (currentValueSignal != null && bottom.ID == currentValueSignal)
                                {
                                    bottomNode.TextColor = Colors.Green;
                                    keyToSelect = bottomNode.Key;
                                }
                                else bottomNode.TextColor = Colors.Blue;
                            }
                        }

                        if (bottomNode != null)
                        {
                            middleNode.ChildNodes.Add(bottomNode);
                            shouldAddMiddleNode = true;
                        }
                    }

                    if (multiplexedTarget != null)
                    {
                        var bottomNode = new SimpleTreeNode{ Key = multiplexedTarget, Text = chinese ? "多路复用信号..." : "Multiplexed signals ..." };
                        middleNode.ChildNodes.Add(bottomNode);
                        shouldAddMiddleNode = true;
                    }

                    if (shouldAddMiddleNode)
                    {
                        if (keyValid) middleNode.ChildNodesExpanded = true;
                        topNode.ChildNodes.Add(middleNode);
                        shouldAddTopNode = true;
                    }
                }

                if (shouldAddTopNode)
                {
                    if (keyValid) topNode.ChildNodesExpanded = true;
                    topNodes.Add(topNode);
                    itemAdded = true;
                }
            }

            treeView.SetModel(topNodes.ToArray(), true);
            if (keyToSelect != null) treeView.SelectItem(keyToSelect);

            return itemAdded;
        }

        private void addNoAvailables()
        {
            var topNode = new SimpleTreeNode{ Key = new object(), Text = chinese ? "(无可用)" : "(No availables)" };
            treeView.SetModel(new SimpleTreeNode[]{ topNode }, false);
        }

        private async void updateSignedLinkProps(LinkButton linkSigned)
        {
            linkSigned.Enabled = false;
            var result = await getSignedLinkProps();
            linkSigned.Text = result.Item1;
            linkSigned.TextColor = result.Item2;
            linkSigned.Enabled = true;
        }

        private async Task<(string, Color)> getSignedLinkProps()
        {
            var signedLinkText = chinese ? "(未配置)" : "(Not configured)";
            var signedLinkColor = Colors.Blue;
            if (currentSignSignal != null)
            {
                var signalName = await AgencyAsync.GetSignalName(currentSignSignal, true);
                if (signalName == null)
                {
                    signedLinkText = currentSignSignal;
                    signedLinkColor = Colors.Red;
                }
                else
                {
                    signedLinkText = signalName;
                    signedLinkColor = Colors.Green;
                }
            }
            return (signedLinkText, signedLinkColor);
        }

        private String currentValueSignal;
        private String currentSignSignal;
        private double? currentScale;
        private bool noAvailables;
        private SimpleTreeView treeView;
        private SearchBox searchBox;
        private Button buttonSelect;

        private bool chinese = AgencyLocal.GetAppLanguage() == Language.Chinese;
    }
}
